
#include <BPainter>
#include <BKeyEvent>
#include <BMouseEvent>
#include <BChangeEvent>
#include <BStyle>

#include <BSlider>
#include "member_BSlider.h"

using namespace BWE;

#define member					(*(member_BSlider*)_ptr)
#define member_allocate()		_ptr = new member_BSlider(this)
#define member_release()		delete (member_BSlider*)_ptr

BSlider::BSlider(BWidget* parent) : BWidget(parent)
{
	member_allocate();
}
BSlider::BSlider(int minimum, int maximum, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setRange(minimum, maximum);
}
BSlider::~BSlider()
{
	member_release();
}

double BSlider::ratio() const
{
	return (double)member.value / (member.maximum - member.minimum);
}

void BSlider::setOrientation(Orientation orientation)
{
	member.orientation = orientation;
	this->fresh();
}
Orientation BSlider::orientation() const
{
	return (Orientation)member.orientation;
}

bool BSlider::set(int value, int min, int max)
{
	if (min > max || value < min || max < value)
		return false;
	this->setValue(value);
	this->setRange(min, max);
	this->fresh();
	return true;
}

bool BSlider::setValue(int value)
{
	if (value != bLimit(value, member.minimum, member.maximum))
		return false;
	if (member.value != value)
	{
		member.value = value;
		this->fresh();
		emit(Signal_ValueChanged, value);
	}
	return true;
}
int BSlider::value() const
{
	return member.value;
}

bool BSlider::setRange(const BRange& range)
{
	return setRange(range.min(), range.max());
}
bool BSlider::setRange(int minimum, int maximum)
{
	if (minimum > maximum)
		return false;
	if(member.minimum != minimum || member.maximum != maximum)
	{
		member.minimum = minimum;
		member.maximum = maximum;
		this->fresh();
		BRange range(minimum, maximum);
		emit(Signal_RangeChanged, range);
	}
	return true;
}
BRange BSlider::range() const
{
	return BRange(member.minimum, member.maximum);
}

bool BSlider::setMinimum(int minimum)
{
	return setRange(minimum, member.maximum);
}
int BSlider::minimum() const
{
	return member.minimum;
}

bool BSlider::setMaximum(int maximum)
{
	return setRange(member.minimum, maximum);
}
int BSlider::maximum() const
{
	return member.maximum;
}

void BSlider::setStep(int step)
{
	if (member.step != step)
	{
		member.step = step;
		emit(Signal_StepChanged, member.step);
	}
}
int BSlider::step() const
{
	return member.step;
}

BSize BSlider::sizeHint() const
{
	BSize hsize = BWidget::sizeHint();
	if (member.orientation & Orientation_Horizontal)
	{
		hsize.set(100, 12);
	}
	if (member.orientation &  Orientation_Vertical)
	{
		hsize.set(12, 100);
	}
	return hsize;
}

void BSlider::resizeEvent(const BEvent& event)
{
	member.rect = this->clientRect();
	if (member.orientation & Orientation_Horizontal)
	{
		int r = member.rect.height() / 2;
		member.rect.left() += r;
		member.rect.right() -= r;
	}
	if (member.orientation & Orientation_Vertical)
	{
		int r = member.rect.width() / 2;
		member.rect.top() += r;
		member.rect.bottom() -= r;
	}
}

void BSlider::freshEvent(const BEvent& event)
{
	member.freshRects();
}
void BSlider::styleEvent(const BEvent& event)
{
	const BStyle* style = this->realStyle();
	BIcon* handleIcon = style->icon(Icon_Handle);
	if (handleIcon)
	{
		member.handleIcon = handleIcon;
		this->fresh();
	}
}
void BSlider::paintEvent(const BEvent& event)
{
	BWidget::paintEvent(event);

	BRect cRect = this->clientRect();
	int cx = cRect.x();
	int cy = cRect.y();
	int cw = cRect.width();
	int ch = cRect.height();

	BPainter painter(this);

	painter.setColor(Color_Text);

	if (member.handleIcon)
	{
		BImage* image = member.handleIcon->image(member.handleState);
		painter.setColor(255, 255, 255);
		painter.drawImage(member.handleRect, image);
	}
	else
	{
		if (member.handleState == State_Pressed)
			painter.setColor(BColor(156, 78, 78));
		else if (member.handleState == State_Hovered)
			painter.setColor(BColor(156, 78, 78) % 60);
		else
			painter.setColor(BColor(156, 78, 78) % 42);
		painter.setPointSmooth(true);
		painter.setPointSize((int)(member.handleRect.width() * 0.8f));
		painter.drawPoint(member.handleRect.center());
	}
}

void BSlider::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.handleState = State_Normal;

}
void BSlider::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	member.handleState = State_Normal;
}

void BSlider::mousePressEvent(const BMouseEvent& mouseEvent)
{
	BPoint pos = mouseEvent.pos();
	if (mouseEvent.button() == Button_Left)
	{
		if (member.handleRect.contain(pos))
		{
			member.handleState = State_Pressed;
			this->fresh();
		}
		else
		{
			BRect crect = this->clientRect();
			if (crect.contain(pos))
			{
				int value = member.valueOfPoint(pos);
				if (setValue(value))
				{
					member.handleState = State_Normal;
					emit(Signal_Sliding, member.value);
				}
			}
		}
	}
}
void BSlider::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if(mouseEvent.button() == Button_Left)
	{
		if (member.handleState == State_Pressed)
		{
			emit(Signal_SlideFinished, member.value);
		}
		member.handleState = State_Normal;
		this->fresh();
	}
}
void BSlider::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	BRect crect = this->clientRect();
	BPoint pos = mouseEvent.pos();
	if (member.handleState == State_Pressed)
	{
		int value = member.valueOfPoint(pos);
		if (setValue(value))
		{
			emit(Signal_Sliding, member.value);
		}
	}
	else
	{
		State handleState = member.handleRect.contain(pos) ? State_Hovered : State_Normal;
		if (member.handleState != handleState)
		{
			member.handleState = handleState;
			this->fresh();
		}
	}
}
void BSlider::mouseWheelEvent(const BMouseEvent& wheelEvent)
{
	int whell = wheelEvent.wheel();
	if (setValue(member.value + whell * member.step))
	{
		emit(Signal_Sliding, member.value);
	}
	this->fresh();
}

